﻿using System;
using System.Configuration;
using System.Linq;
using System.Web;
using Medianamik.Core.Logging;
using Medianamik.Core.Urls;

namespace Medianamik.Core.Redirect
{
    public class RedirectHttpModule : IHttpModule
    {
        private static readonly ILogger Logger = new ObjectFactory<ILogger>()
            .Get("UrlRewriterLogger");

        /// <summary>
        /// Initializes a module and prepares it to handle requests.
        /// </summary>
        /// <param name="context">An <see cref="T:System.Web.HttpApplication" /> that provides access to the methods, properties, and events common to all application objects within an ASP.NET application </param>
        public void Init(HttpApplication context)
        {
            context.BeginRequest += ContextBeginRequest;
        }

        public virtual IUrlDictionaryProcess UrlProcess
        {
            get
            {
                return new ObjectFactory<IUrlDictionaryProcess>().Get();
            }
        }

        /// <summary>
        /// Disposes of the resources (other than memory) used by the module that implements <see cref="T:System.Web.IHttpModule" />.
        /// </summary>
        public void Dispose()
        {

        }

        void ContextBeginRequest(object sender, EventArgs e)
        {
            System.Action doRedirect = null;

            try
            {
                var app = (HttpApplication)sender;

                if (UrlProcess.ThisUrlRedirectMustBeProcessWithDictionnary(app.Request.Url))
                {
                    if (RedirectDictionary.Instance.ContainsUrl(app.Request.Url.ToString()))
                    {
                        var entry = RedirectDictionary.Instance.GetEntry(app.Request.Url.ToString());
                        var url = entry.UrlDictionaryEntry.RequestedUrl.AbsoluteUri;
                        
                        if (entry.QueryString.Count > 0)
                        {
                            url += '?' + entry.QueryString.ToString();
                        }

                        doRedirect = () => app.Response.Redirect(url, entry.ResponseCode);
                    }
                    else
                    {
                        var redirect = ExternalRedirectDictionary.Instance.GetEntry(app.Request.Url.ToString());
                        
                        if (redirect != null)
                        {
                            doRedirect = () => app.Response.Redirect(redirect.RedirectTo, redirect.ResponseCode);
                        }
                        else
                        {
                            //Ajout par CS 2010-06-11, pour le support des dossiers dans les redirections 
                            //Cette section est bypassée si l'Url passé existe dans le dictionnaire des Urls
                            var requestedUrl = app.Request.RawUrl;
                            var urlDictionary = new ObjectFactory<IUrlDictionary>().Get();

                            if (requestedUrl != null && !urlDictionary.ContainsUrl(string.Format("http://{0}{1}",
                                app.Request.Url.Authority, requestedUrl)))
                            {
                                var entries = RedirectDictionary.Instance.Where(rd => rd.RedirectFromPath.EndsWith("*") &&
                                      rd.RedirectFromUri.Authority == app.Request.Url.Authority)
                                      .OrderByDescending(rd => rd.RedirectFromPath.Length);

                                //Si l'url demandé est dans le dictionnaire des URLS, ce dernier a priorité et ce code ne sera pas exécuté
                                if (entries.Count() > 0)
                                {
                                    //Pour chacun des "paths" trouvés (s'il y a lieu), je cherche pour savoir si l'URL courant correspond à une des redirections de path 
                                    var url = string.Empty;

                                    var entryFound = (entries.FirstOrDefault(delegate(RedirectDictionaryEntry entry)
                                     {
                                         if (requestedUrl.Contains(entry.RedirectFromPath.Replace("*", string.Empty)))
                                         {
                                             url = entry.UrlDictionaryEntry.RequestedUrl.AbsoluteUri;

                                             if (entry.QueryString.Count > 0)
                                             {
                                                 url += '?' + entry.QueryString.ToString();
                                             }

                                             return true;
                                         }

                                         return false;
                                     }));

                                    //Redirection après la boucle, si une redirection a été trouvée
                                    if (!string.IsNullOrEmpty(url) && entryFound != null)
                                    {
                                        doRedirect = () => app.Response.Redirect(url, entryFound.ResponseCode);
                                    }
                                }
                            }
                        }
                    }
                }
            }
            catch (Exception exc)
            {
                Logger.Fatal("Erreur dans le module de redirection", exc);

                //var app = (HttpApplication)sender;
                //app.Response.Redirect(GetError500URL());
            }

            if (doRedirect != null)
            {
                doRedirect();
            }
        }
    }
}